import UglifyJS from "../../uglify-js/tools/node.js";

export function randomWord(range) {
    var str = "",
        arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

    var arr2 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_', '$'];

    // arr = ['$'];
    // 随机产生
    for (var i = 0; i < range; i++) {
        if (i == 0) {
            let pos = Math.round(Math.random() * (arr.length - 1));
            str += arr[pos];
        } else {
            let pos = Math.round(Math.random() * (arr2.length - 1));
            str += arr2[pos];
        }
    }
    return str;
}

export function xor_enc(str, key) {
    var crytxt = '';
    var k, keylen = key.length;
    for(var i=0; i<str.length; i++) {
        k = i % keylen;
        crytxt += String.fromCharCode(str.charCodeAt(i) ^ key.charCodeAt(k));
    }
    return crytxt;
}



export class RubbishJSObfuscator {
    origCode = null;
    code = null;
    topLevel = null;

    constructor(code) {
        this.origCode = code;
        this.code = code;
        this.topLevel = UglifyJS.parse(this.code, {
            bare_returns: true
        }); //toplevel就是语法树

    }

    generateCode() {
        //从AST还原成字符串
        this.code = this.topLevel.print_to_string(
            {
                beautify: true,
            });
        return this.code;
    }

    dot2String() {
        // let toplevel = UglifyJS.parse(this.code); //toplevel就是语法树
        let toplevel = this.topLevel;

        function newNode(node) {
            if (node instanceof UglifyJS.AST_Dot) {
                // if (node.property === "_super") {
                //     // cocos 引擎使用了/\b\._super\b/来测试直接测试函数的字符串形式，所以["_super"]检查不到
                //     return node;
                // }
                if (typeof node.property === "string") {
                    return new UglifyJS.AST_Sub({
                        expression: newNode(node.expression),
                        property: new UglifyJS.AST_String({value: node.property}),
                    })
                }
                else {
                    return node;
                }
            }
            return node;
        }
        let transformer = new UglifyJS.TreeTransformer(function(node) {
            if (node instanceof UglifyJS.AST_Dot) {
                if (typeof node.property === "string") {
                    return newNode(node);
                }
            }
        });
        toplevel.transform(transformer); //遍历AST树
    }

    processString() {
        let toplevel = this.topLevel

        let strSet = new Set();
        // collect string
        let transformer = new UglifyJS.TreeTransformer(function(node) {
            if (node instanceof UglifyJS.AST_String) {
                strSet.add(node.value)
            }
            if (node instanceof UglifyJS.AST_Number) {
                strSet.add(node.value);
            }
        });
        toplevel.transform(transformer); //遍历AST树

        let strList = Array.from(strSet);
        strList.sort(function() {
            return 0.5 - Math.random()
        });

        let strListName = `$${randomWord(16)}`;

        let max = 50;
        let min = 5;
        let len = Math.floor(Math.random()*(max-min)+min);  // 每个元素多长

        let outputJson = [];
        let listNameList = [];
        let head = "";
        for (let i = 0; i < strList.length; i++) {
            if (i % len === 0) {
                outputJson.push([]);
                let name = `$${randomWord(16)}`;
                listNameList.push(name);
                head += `var ${name} = ${strListName}[${Math.floor(i / len)}];\n`
            }
            outputJson[Math.floor(i / len)].push(strList[i]);
        }

        function getListName(index) {
            return listNameList[Math.floor(index / len)];
        }

        function getNewIndex(index) {
            return index % len;
        }

        function getValueSymbol(str) {
            let index = strList.indexOf(str);
            let strListName = getListName(index);
            index = getNewIndex(index);
            return {
                symbol: strListName,
                index: index
            };
        }

        transformer = new UglifyJS.TreeTransformer(function(node) {
            if (node instanceof UglifyJS.AST_String || node instanceof UglifyJS.AST_Number) {
                //查找需要修改的叶子节点
                let {symbol, index} = getValueSymbol(node.value);
                return new UglifyJS.AST_Sub({
                    expression:  new UglifyJS.AST_SymbolRef({
                        name: symbol
                    }),
                    property: new UglifyJS.AST_Number({
                        value: index
                    }),
                })
            }
        });
        toplevel.transform(transformer); //遍历AST树

        let jsonStr = JSON.stringify(outputJson);
        let xorKey = randomWord(8);
        let xorResult = xor_enc(jsonStr, xorKey);

        let base64 = Buffer.from(xorResult).toString("base64");

        head = `
let ${strListName} = function(e) {
    var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var t = "";
    var n, r, i;
    var s, o, u, a;
    var f = 0;
    e = e.replace(/[^A-Za-z0-9+/=]/g, "");
    while (f < e.length) {
        s = _keyStr.indexOf(e.charAt(f++));
        o = _keyStr.indexOf(e.charAt(f++));
        u = _keyStr.indexOf(e.charAt(f++));
        a = _keyStr.indexOf(e.charAt(f++));
        n = s << 2 | o >> 4;
        r = (o & 15) << 4 | u >> 2;
        i = (u & 3) << 6 | a;
        t = t + String.fromCharCode(n);
        if (u != 64) {
            t = t + String.fromCharCode(r)
        }
        if (a != 64) {
            t = t + String.fromCharCode(i)
        }
    }
    return function(e) {
		var t = "";
		var n = 0;
		var c1,c2,c3;
		var r = c1 = c2 = 0;
		while (n < e.length) {
			r = e.charCodeAt(n);
			if (r < 128) {
				t += String.fromCharCode(r);
				n++
			} else if (r > 191 && r < 224) {
				c2 = e.charCodeAt(n + 1);
				t += String.fromCharCode((r & 31) << 6 | c2 & 63);
				n += 2
			} else {
				c2 = e.charCodeAt(n + 1);
				c3 = e.charCodeAt(n + 2);
				t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
				n += 3
			}
		}
		return t
	}(t);
}("${base64}");
!function() {
    ${strListName} = function(str, key) {
        var crytxt = '';
        var k, keylen = key.length;
        for(var i=0; i<str.length; i++) {
            k = i % keylen;
            crytxt += String.fromCharCode(str.charCodeAt(i) ^ key.charCodeAt(k));
        }
        return crytxt;
    }(${strListName}, "${xorKey}");
    ${strListName} = JSON.parse(${strListName});
}();
${head}
`;


        let code = this.generateCode();
        this.code = head + code;
    }

    uglifyJSMinify() {
        let result = UglifyJS.minify(this.code, {
            compress: false,
            mangle: {
                properties: false,
                reserved: ['wx'],
                toplevel: true,
                // base54BeginNum: base54BeginNum,
            },
            output: {
                code: true // optional - faster if false
            },
            parse: {
                bare_returns: true
            }
        });
        if (result.error) {
            debugger
            console.log(result.error)
        }

        this.code = `// ${new Date()}\n` + result.code;
        return this.code;
    }
}
